package mss

import (
	"encoding/hex"
	"fmt"
	"mss/internal/app/common"
	"mss/internal/salvedev"
	"mss/internal/utils"
	"net"
	"os"
	"path"
	"strconv"
	"strings"

	"gopkg.in/yaml.v2"
)

func parseDeviceRange(which string) (map[uint][]byte, error) {
	portAddrs := make(map[uint][]byte, 0)

	for _, port := range strings.Split(which, ",") {
		addrs := strings.Split(port, ":")
		if len(addrs) != 2 {
			return nil, fmt.Errorf("参数格式错误")
		}

		tcpPort, err := strconv.Atoi(addrs[0])
		if err != nil {
			return nil, fmt.Errorf("参数格式错误")
		}

		fields := strings.Split(addrs[1], "-")
		if len(fields) != 2 {
			return nil, fmt.Errorf("参数格式错误")
		}

		addr1, _ := strconv.Atoi(fields[0])
		addr2, _ := strconv.Atoi(fields[1])

		if addr1 < 1 || addr1 > 125 || addr2 < 1 || addr2 > 125 {
			return nil, fmt.Errorf("参数格式错误")
		}

		portAddrs[uint(tcpPort)] = make([]byte, 0)

		for addr := addr1; addr <= addr2; addr++ {
			portAddrs[uint(tcpPort)] = append(portAddrs[uint(tcpPort)], byte(addr))
		}
	}

	return portAddrs, nil
}

func getDeviceObjFromFile(filename string) (*BoostDevice, error) {
	dataNew, err := os.ReadFile(filename)
	if err != nil {
		return nil, err
	}
	objNew := &BoostDevice{}
	err = yaml.Unmarshal(dataNew, objNew)
	if err != nil {
		return nil, err
	}

	return objNew, nil
}

// BatchAddDevices 批量添加设备
func BatchAddDevices(which string) error {
	all, _ := parseDeviceRange(which)
	for port, addrs := range all {
		for _, addr := range addrs {
			filepath := path.Join(utils.CurrentExePath(), common.DevicesPath, fmt.Sprintf("%d_%d.yml", port, addr))
			dev := &BoostDevice{TcpPort: port, SalveAddr: addr}
			if data, err := yaml.Marshal(dev); err == nil {
				os.WriteFile(filepath, data, 0644)
			}
		}
	}

	return nil
}

// BatchUpdateDevices 批量修改设备
func BatchUpdateDevices(which, settingFile string) error {
	dataNew, err := os.ReadFile(settingFile)
	if err != nil {
		return err
	}
	objNew := &BoostDevice{}
	err = yaml.Unmarshal(dataNew, objNew)
	if err != nil {
		return err
	}

	files, _ := os.ReadDir(utils.CurrentExePath() + common.DevicesPath)

	all, _ := parseDeviceRange(which)
	for port, addrs := range all {
		for _, addr := range addrs {
			for _, f := range files {
				filename := path.Join(utils.CurrentExePath(), common.DevicesPath, f.Name())
				old, err := getDeviceObjFromFile(filename)
				if err != nil {
					continue
				}

				if old.TcpPort == port && old.SalveAddr == addr {
					for j := range objNew.Values {
						existed := false
						for i := range old.Values {
							if old.Values[i].Addr == objNew.Values[j].Addr && old.Values[i].FunctionCode == objNew.Values[j].FunctionCode {
								old.Values[i] = objNew.Values[j]
								existed = true
								break
							}
						}
						if !existed {
							old.Values = append(old.Values, objNew.Values[j])
						}
					}
					if data, err := yaml.Marshal(old); err == nil {
						err = os.WriteFile(filename, data, 0644)
						fmt.Fprintf(os.Stdout, "[config] 程序中更新配置文件%s:%v\n", f.Name(), err)
					}
					break
				}
			}
		}
	}
	return nil
}

// Run 运行服务入口，非阻塞
func Run() error {
	//创建设备目录
	os.Mkdir(common.DevicesPath, 0777)

	//监控设备目录
	go watchConfig(common.DevicesPath)

	//
	//从设备目录中加载设备列表
	//

	files, _ := os.ReadDir(utils.CurrentExePath() + common.DevicesPath)
	for _, f := range files {
		if f == nil || f.IsDir() {
			continue
		}
		if !strings.HasSuffix(f.Name(), ".yml") {
			continue
		}
		data, err := os.ReadFile(path.Join(utils.CurrentExePath(), common.DevicesPath, f.Name()))
		if err != nil {
			continue
		}

		d := &BoostDevice{}
		err = yaml.Unmarshal(data, d)
		if err != nil {
			continue
		}

		d.filename = f.Name()
		d.salvedev = salvedev.NewModbusSlave(d.SalveAddr)

		devices.Store(d.Key(), d)
	}

	count := 0
	devices.Range(func(key, value any) bool {
		count++
		d := value.(*BoostDevice)
		fmt.Printf("已加载设备设备:tcp=%d,salve_addr=%d\n", d.TcpPort, d.SalveAddr)
		return true // 继续遍历
	})
	fmt.Printf("共加载设备设备%d个\n", count)

	//
	//开启监听服务
	//

	ports := make(map[uint]struct{}, 0)
	devices.Range(func(key, value any) bool {
		d := value.(*BoostDevice)
		ports[d.TcpPort] = struct{}{}
		return true // 继续遍历
	})

	for port := range ports {
		go tcpListening(port)
	}

	return nil
}

func tcpListening(port uint) {
	listener, err := net.Listen("tcp", fmt.Sprintf(":%d", port))
	if err != nil {
		return
	}

	for {
		conn, err := listener.Accept()
		if err != nil {
			return
		}

		go handleConn(conn, port)
	}
}

func handleConn(conn net.Conn, port uint) {
	defer conn.Close()

	buf := make([]byte, 256)
	for {
		n, err := conn.Read(buf[0:])
		if err != nil {
			return
		}

		fmt.Printf("[IO] 端口(%d)请求:%v\n", port, hex.EncodeToString(buf[:n]))

		// 检查CRC
		if n < 4 { // 最小帧长度(1地址 + 1功能码 + 2CRC)
			continue
		}

		d, ok := devices.Load(fmt.Sprintf("%d:%d", port, buf[0]))
		if !ok {
			continue
		}

		dev := d.(*BoostDevice)

		// 处理请求前，先更新寄存器的值
		dev.UpdateValues()

		// 处理请求(去掉CRC)
		response, err := dev.salvedev.ProcessRequest(buf[:n-2])
		if err != nil {
			continue
		}

		// 计算并添加CRC
		crc := calculateCRC(response)
		fullResponse := append(response, crc...)

		fmt.Printf("[IO] 端口(%d)响应:%v\n", port, hex.EncodeToString(fullResponse))

		//返回数据
		conn.Write(fullResponse)
	}
}

// calculateCRC 计算Modbus RTU CRC校验
func calculateCRC(data []byte) []byte {
	var crc uint16 = 0xFFFF
	for _, b := range data {
		crc ^= uint16(b)
		for i := 0; i < 8; i++ {
			if crc&0x0001 != 0 {
				crc >>= 1
				crc ^= 0xA001
			} else {
				crc >>= 1
			}
		}
	}
	return []byte{byte(crc), byte(crc >> 8)}
}
